#ifndef LIZA_H
#define LIZA_H

#include <iostream>
#include <vector>
#include <string>
#include <llvm/Module.h>
#include <llvm/Function.h>
#include <llvm/DerivedTypes.h>
#include <llvm/Constants.h>
#include <llvm/PassManager.h>
#include <llvm/CallingConv.h>
#include <llvm/Analysis/Verifier.h>
#include <llvm/Assembly/PrintModulePass.h>
#include <llvm/Support/LLVMBuilder.h>

using namespace llvm;

using namespace std;

enum NodeType{
  nPROGRAM,
  nBLOCK,
  nDEF,
  nDEF_DEFINE,
  nDEF_PARAM,
  nDEF_PARAMS,
  nLOOP,
  nBLANK,
  nASSIGN,
  nEQUALS,
  nIDENT,
  nGIDENT,
  nINVOKE,
  nPARAM,
  nPARAMS,
  nSTRING_VALUE,
  nINTEGER_VALUE,
  nBOOLEAN_VALUE,
  nSTRING_EXPRESSION,
  nINTEGER_EXPRESSION,
  nBOOLEAN_EXPRESSION,
  nINTEGER_CONSTANT,
  nSTRING_CONSTANT,
  nSTRING_PLUS,  
  nADD,
  nDIV
};

enum DataType{
  tINTEGER,
  tSTRING,
  tBOOLEAN
};


enum SymbolType{
  sID,
  sGID,
  sCONSTANT
};

class SymbolNode {

  public:

  SymbolNode( ){
  }

  SymbolNode( SymbolType type  ){
    this->symbolType = type;
  }

  SymbolNode( SymbolType type , DataType dataType){
    this->symbolType = type;
    this->dataType = dataType;
  }

  SymbolNode( SymbolType type , DataType dataType, string &name){
    this->symbolType = type;    
    this->name = name;
    this->dataType = dataType;
  }

  string name;

  string s_value;

  bool b_value;

  int i_value;
 
  SymbolType symbolType;
  
  DataType dataType;

  Type* type;
  
};

class CodeGenerator;

class TreeNode {
  
  public:
  TreeNode( NodeType nodeType ) {
    this->nodeType = nodeType;
    child = vector<TreeNode>();    
  } 

  TreeNode( NodeType nodeType,
	    DataType dataType ) {
    this->nodeType = nodeType;
    this->dataType = dataType;
    child = vector<TreeNode>();
  }  

  NodeType nodeType;

  DataType dataType;  
  
  vector<TreeNode> child;

  SymbolNode *symbolNode;

  Value* value;

  CodeGenerator codeGen();

  LLVMBuilder builder; 
  
  Module *module;
  
  BasicBlock *block;
};

class LoopNode : public TreeNode{

 public:
  LoopNode()
    :TreeNode(nLOOP){
  }

  BasicBlock *condBlock;
  BasicBlock *entryBlock;
  BasicBlock *nextBlock;
  Value *incrVar;
  Value *cond;
};

class CodeGenerator{
 
 public:
  CodeGenerator(){
  };

  virtual string codeGen();
};

#endif
